Scala の cake pattern
code:scala
// =======================
// サービスインターフェイス
trait OnOffDeviceComponent {
val onOff: OnOffDevice
trait OnOffDevice {
def on: Unit
def off: Unit
}
}
trait SensorDeviceComponent {
val sensor: SensorDevice
trait SensorDevice {
def isCoffeePresent: Boolean
}
}
// =======================
// サービス実装
trait OnOffDeviceComponentImpl extends OnOffDeviceComponent {
class Heater extends OnOffDevice {
def on = println("heater.on")
def off = println("heater.off")
}
}
trait SensorDeviceComponentImpl extends SensorDeviceComponent {
class PotSensor extends SensorDevice {
def isCoffeePresent = true
}
}
// =======================
// 二つの依存オブジェクトへの依存性を宣言したサービス
trait WarmerComponentImpl {
this: SensorDeviceComponent with OnOffDeviceComponent =>
class Warmer {
def trigger = {
if (sensor.isCoffeePresent) onOff.on
else onOff.off
}
}
}
// =======================
// モジュール内でサービスのインスタンスを生成する
object ComponentRegistry
extends OnOffDeviceComponentImpl
with SensorDeviceComponentImpl
with WarmerComponentImpl {
val onOff = new Heater
val sensor = new PotSensor
val warmer = new Warmer
}
// =======================
val warmer = ComponentRegistry.warmer
warmer.trigger
自分型 annotation (self-type annotation)
code:scala
// =======================
// サービスインターフェイス
trait OnOffDevice {
def on: Unit
def off: Unit
}
trait SensorDevice {
def isCoffeePresent: Boolean
}
// =======================
// サービス実装
class Heater extends OnOffDevice {
def on = println("heater.on")
def off = println("heater.off")
}
class PotSensor extends SensorDevice {
def isCoffeePresent = true
}
// =======================
// 構造的部分型を用いて二つの依存オブジェクトへの
// 依存性を宣言したサービス
class Warmer(env: {
val potSensor: SensorDevice
val heater: OnOffDevice
}) {
def trigger = {
if (env.potSensor.isCoffeePresent) env.heater.on
else env.heater.off
}
}
class Client(env: { val warmer: Warmer }) {
env.warmer.trigger
}
// =======================
// 構成モジュールにおいてサービスのインスタンスを生成する
object Config {
lazy val potSensor = new PotSensor
lazy val heater = new Heater
lazy val warmer = new Warmer(this) // this is where injection happens
}
new Client(Config)
minimal cake pattern
code:scala
trait UsesUserRepository {
val userRepository: UserRepository
}
trait UserRepository {
// 略
}
trait MixInUserRepository extends UsesUserRepository {
val userRepository = UserRepositoryImpl
}
object UserRepositoryImpl extends UserRepository {
// 略
}
trait UserService extends UsesUserRepository {
// 略
}
object UserService extends UserService with MixInUserRepository